#define LOG_NDEBUG 0
#define LOG_TAG "NetAPCP"

#include "ap/NetAPCP.h"

#include <ipcp/ipcp.h>
#include <ipcp/packet.h>
#include "VHalLog.h"
#include <transfer/SafeQueue.h>
#include <transfer/SignalStorage.h>
#include <transfer/utils.h>
#include <android-base/properties.h>

#include <set>
#include <thread>

#include "ap/APCP_signal_id.h"
#include "common.h"
#include "apcp_ipcp_2_signal.h"
#include "apcp_signal_2_ipcp.h"


#define INVALID_SERVICE_ID 0x0

#define SEND_RETRY_MAX_COUNT 3
#define PACKET_HEADER_OFFSET IPCP_LEAST_LEN
#define RETRY_TRANSPORT_CONF_MAX_COUNT 5
#include "ap/APCPSignalManager.h"
namespace ecarx::transfer::apcp {

    static utils::ConcurrentQueue<ecarx::transfer::ipcp::IpcpValue> mIpcpQueue;
    static utils::BatchingConsumer<ecarx::transfer::ipcp::IpcpValue> mBatchingConsumer;

    static std::set<uint16_t> packageReceived;

    template<typename T, size_t N = sizeof(T)>

    std::vector<uint8_t> toBytes(T value) {
        std::vector<uint8_t> data;
        data.resize(N, 0);
        memcpy(data.data(), &value, N);
        return data;
    }

    class APCPConn::NetAPCP {
    public:
        NetAPCP() {
            mState = NetState::INIT;
            mBatchingConsumer.run(&mIpcpQueue,
                                  std::bind(&NetAPCP::readThread, this, std::placeholders::_1));
            mIPCPCallbacks = new ipcp_callbacks_t;
            mIPCPCallbacks->ipcp_received_cb = netReceived;
            mIPCPCallbacks->error_cb = error_cb;
            initTransport_conf();
            VHALOG.d("apcp init construct");
        }

        ~NetAPCP() {
            VHALOG.d("apcp release");
            mBatchingConsumer.requestStop();
            mIpcpQueue.deactivate();
            // We have to wait until consumer thread is fully stopped because it may
            // be in a state of running callback (onBatchHalEvent).
            mBatchingConsumer.waitStopped();
            close();
        }

        //打开链接
        bool open() {
            notifyNetState(NetState::Open);
            VHALOG.d("dbgstart jdbg APCP isDebugMode:%d cp:%s ihu:%s", ecarx::transfer::ipcp::IsDebugMode(),
            ecarx::transfer::ipcp::GetCPIP(), ecarx::transfer::ipcp::GetAPIP());
            int error_code = STACK_START_SUCCESS;
            for (const ipcp_transport_conf_t conf : mTransportConfigs) {
                int retryTransportConfCount = 0;
                do {
                    ValidOperationArray opIdsArray = getValidOperationArray(conf.service_id);
                    error_code = ipcp_setup_with_opids(conf,
                                                       mIPCPCallbacks,
                                                       opIdsArray.oper_ids,
                                                       opIdsArray.len);
                    if (error_code != STACK_START_SUCCESS) {
                        VHALOG.e("funtion: %s, apcp_setup_with_opids service id 0x%x ,failed, errno=%d",
                              __FUNCTION__, conf.service_id, error_code);
                        if (error_code == STACK_FAILURE_CREATE_SOCKET ||
                            error_code == STACK_FAILURE_SET_VLAN ||
                            error_code == STACK_FAILURE_BIND_SOCKET ||
                            error_code == STACK_FAILURE_LISTEN_SOCKET ||
                            error_code == STACK_FAILURE_ACCEPT_SOCKET ||
                            error_code == STACK_FAILURE_CONNECT_SOCKET ||
                            error_code == STACK_FAILURE_CREATE_THREAD ||
                            error_code == STACK_FAILURE_PARM_INVALID) {
                            VHALOG.e("funtion: %s, apcp_setup_with_opids service id 0x%x failed , check retry",
                                  __FUNCTION__, conf.service_id);
                            retryTransportConfCount++;
                            if (retryTransportConfCount > RETRY_TRANSPORT_CONF_MAX_COUNT) {
                                VHALOG.e("funtion: %s, apcp_setup_with_opids service id 0x%x retry %d times failed",
                                      __FUNCTION__, RETRY_TRANSPORT_CONF_MAX_COUNT, conf.service_id);
                                break;
                            }
                            std::this_thread::sleep_for(std::chrono::milliseconds(50));
                        } else {
                            VHALOG.e("funtion: %s, apcp_setup_with_opids service id 0x%x no need to retry",
                                  __FUNCTION__, conf.service_id);
                            break;
                        }
                    }
                } while (error_code != STACK_START_SUCCESS);
                VHALOG.d("funtion: %s, apcp_setup_with_opids service id 0x%x done", __FUNCTION__, conf.service_id);
            }
            openState = error_code == STACK_START_SUCCESS;
            if (openState) {
                VHALOG.d("dbgstart open apcp success");
                getAll();
                notifyNetState(NetState::Ready);
            } else {
                VHALOG.e("dbgstart open apcp failed");
            }
            return openState;
        }
        //关闭链接
        bool close() {
            notifyNetState(NetState::Close);
            ipcp_cleanup();
            return true;
        }
        //将数据写到网络上
        bool write(const Signal& signal) {
            ecarx::transfer::ipcp::IpcpValue ipValue =
                    ecarx::transfer::utils::cpSignalToIpcpValue(signal);
            ipcp_packet_t *packet =
                    build_ipcp_packet(ipValue.service_id, ipValue.oper_id, ipValue.oper_type,
                                      ipValue.payload_type, ipValue.payload, ipValue.payload_len);
            VHALOG.e("apcp send:service_id=[0x%x],oper_id=[0x%x],oper_type=[%d],payload_type=[%d],payload_len=[%ld]",
                  ipValue.service_id, ipValue.oper_id, ipValue.oper_type,
                  ipValue.payload_type, static_cast<long>(ipValue.payload_len));
            if (ipValue.payload_len > 0) {
                delete[](uint8_t*) ipValue.payload;  // release asn1 payload buffer, ipcp stack
                                                     // already copy buffer to itself.
            }
            if (packet != NULL) {
                ipcp_peer_t peer;
                memset(peer.peer_ip, 0, sizeof(peer.peer_ip));
                strcpy(peer.peer_ip, ipValue.peer_ip);  // service ip
                peer.peer_port = ipValue.peer_port;
                peer.sk_type = IPCP_TRANSPORT_UDP;
                ipcp_stack_err_t err = STACK_SEND_MSG_SUCCESS;
                if ((err = ipcp_send(peer, packet)) != STACK_SEND_MSG_SUCCESS) {
                    VHALOG.e("funtion: %d, apcp_send err : %d", signal.signalId, err);
                    return false;
                }
                return true;
            } else {
                VHALOG.e("funtion: %d, apcp build packet failed is not writeable", signal.signalId);
            }
            return false;
        }
        const std::optional<Signal> read(const int32_t signalId) const {
            return mAPCPStorage.get(signalId);
        }

        NetState getState(){
            return mState;
        }

        void notifyNetState(NetState state) {
            mState = state;
            if (mStateCallback != nullptr) {
                mStateCallback(state);
            }
        }

        void onSignalChanged(SignalChangeCallback &&callback) { mSignalChangeCallback = callback; }

        void registerStateHandler(NetStateCallback &&callback) { mStateCallback = callback; }

        //接受网络上的数据回调
        static void netReceived(ipcp_packet_t *packet, ipcp_peer_t peer) {
            std::size_t payload_len = packet->header.length - PACKET_HEADER_OFFSET;
            if (payload_len > 0) {
                ecarx::transfer::ipcp::IpcpValue value;
                value.service_id = packet->header.service_id;
                value.oper_id = packet->header.operation_id;
                value.oper_type = packet->header.op_type;
                value.payload_type = packet->header.payload_type;
                if(packet->header.op_type == IPCP_OPERATION_ERROR){
                    VHALOG.e("apcp service id %d opid 0x%x rcv ERROR msg, ignore!", packet->header.service_id,
                    packet->header.operation_id);
                    return;
                }
                // service ip
                memset(value.peer_ip, 0, sizeof(value.peer_ip));
                strcpy(value.peer_ip, peer.peer_ip);
                // service port
                value.peer_port = peer.peer_port;
                // payload
                value.payload_len = payload_len;
                value.payload = (void *) new uint8_t[value.payload_len];
                memcpy(value.payload, packet->payload, value.payload_len);
                VHALOG.d("APCP funtion: %s, apcp service id 0x%x opid 0x%x ", __FUNCTION__, packet->header.service_id,
                      packet->header.operation_id);
                mIpcpQueue.push(std::move(value));
            }
        }

        static void error_cb(ipcp_packet_t *ipcp_packet, ipcp_stack_err_t error) {
            VHALOG.d("APCP funtion: %s, apcp service id 0x%x opid 0x%x ipcp stack error : %d", __FUNCTION__,
                  ipcp_packet->header.service_id, ipcp_packet->header.operation_id, error);
        }

    private:
        void initTransport_conf() {
            const char* apip = ecarx::transfer::ipcp::GetAPIP();
            uint16_t CP_IPCP_SERVICES[] = {
                CP_serviceID_Normal,
                CP_serviceID_TimeSync,
                CP_serviceID_AVAS,
                CP_serviceID_HostInfo,
                CP_serviceID_Power,

            };
            // 初始化APCP 通信 IPCP端口
            for (int i = 0; i < (sizeof(CP_IPCP_SERVICES) / sizeof(CP_IPCP_SERVICES[0])); i++) {
                ipcp_transport_conf_t cfg = {.service_id = CP_IPCP_SERVICES[i],
                                        .host_port = AP_LOCAL_PORT,
                                        .sk_type = IPCP_TRANSPORT_UDP,
                                        .vlan = AP_VLAN_ID,
                                        .priority = AP_VLAN_PRIORITY,
                                        .eth = "eth0"};
                VHALOG.d("APCP initTransport_conf funtion: %s, apcp service id 0x%x  ", __FUNCTION__, CP_IPCP_SERVICES[i]);
                strcpy(cfg.host_ip, apip);
                mTransportConfigs.emplace_back(cfg);
            }
            
        }

        void readThread(const ecarx::transfer::ipcp::IpcpValue &value) {
            // 从netReceive的data分析数据内容
            std::vector<int32_t> changed;
            if (value.service_id == CP_serviceID_Normal ||
                value.service_id == CP_serviceID_TimeSync ||
                value.service_id == CP_serviceID_AVAS ||
                value.service_id == CP_serviceID_HostInfo ||
                value.service_id == CP_serviceID_Power) {
                // 信号
                std::vector<ecarx::transfer::Signal> buffer = ecarx::transfer::utils::cpIpcpValueToSignal(value);
                mAPCPStorage.put(buffer, changed);
            }
            if (!changed.empty()) {
                mSignalChangeCallback(changed);
            }
            delete[](uint8_t *) value.payload;
        }

        void getAll() {
            const char* cpip = ecarx::transfer::ipcp::GetCPIP();

            VHALOG.e("APCP getall");
            std::map<int32_t, int32_t> svcIdPortMap = {
                {CP_serviceID_Normal, CP_SERVICE_NORMAL_PORT},
                {CP_serviceID_TimeSync, CP_SERVICE_TIME_PORT},
                {CP_serviceID_AVAS, CP_SERVICE_AVAS_PORT},
                {CP_serviceID_HostInfo, CP_SERVICE_HOSTINFO_PORT},
                {CP_serviceID_Power, CP_SERVICE_POWER_PORT},
            };
            size_t bufLen = sizeof(OpStatus2CpNormal_SetRequestNoReturn);
            OpStatus2CpNormal_SetRequestNoReturn *buffer = (OpStatus2CpNormal_SetRequestNoReturn *)new uint8_t[bufLen];
            (*buffer).value = (uint8_t)1;
            for (const ipcp_transport_conf_t conf : mTransportConfigs) {
                ipcp_packet_t* packet = build_ipcp_packet(
                    conf.service_id, 0x1001, IPCP_OPERATION_SETREQUEST_NORETURN, IPCP_DATA_NORMAL, buffer, bufLen);
                if (packet != NULL) {
                    ipcp_peer_t peer;
                    memset(peer.peer_ip, 0, sizeof(peer.peer_ip));
                    strcpy(peer.peer_ip, cpip);  // service ip
                    peer.peer_port = svcIdPortMap[conf.service_id];
                    peer.sk_type = IPCP_TRANSPORT_UDP;
                    ipcp_stack_err_t err = STACK_SEND_MSG_SUCCESS;
                    if ((err = ipcp_send(peer, packet)) != STACK_SEND_MSG_SUCCESS) {
                        VHALOG.e("APCP funtion: %s,ipcp_send err : %d, svcId:0x%x, port:%d", __FUNCTION__, err,conf.service_id,peer.peer_port);
                    } else {
                         VHALOG.d("APCP send succ svcId:0x%x, port:%d", conf.service_id,peer.peer_port);
                    }
                } else {
                    VHALOG.e("APCP funtion:%s , build  packet failed is not readable", __FUNCTION__);
                }
            }
            delete[](uint8_t *) buffer;
        
        }


  private:
    std::unique_ptr<std::thread> mReadThread;

        SignalChangeCallback mSignalChangeCallback;
        NetStateCallback mStateCallback;

        ipcp_callbacks_t *mIPCPCallbacks;

        std::vector<ipcp_transport_conf_t> mTransportConfigs;
        storage::SignalPool mAPCPStorage;
        NetState mState;
        bool openState = false;
    };

    APCPConn::APCPConn() : mImpl(new NetAPCP()) {}

    APCPConn::~APCPConn() {
        delete mImpl;
    }

    bool APCPConn::open() {
        return mImpl->open();
    }

    bool APCPConn::close() {
        return mImpl->close();
    }

    bool APCPConn::write(const Signal &signal) {
        return mImpl->write(signal);
    }

    const std::optional<Signal> APCPConn::read(const int32_t signalId) const {
        return mImpl->read(signalId);
    }

    NetState APCPConn::getState() {
        return mImpl->getState();
    }

    void APCPConn::onSignalChanged(SignalChangeCallback &&callback) {
        mImpl->onSignalChanged(std::move(callback));
    }

    void APCPConn::registerStateHandler(NetStateCallback &&callback) {
        mImpl->registerStateHandler(std::move(callback));
    }

}  // namespace ecarx::transfer::ipcp
